
/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 沈明月
 * Date: 2022-11-30
 * Time: 12:25
 */

//多态：多种形态。完成某个行为，当不同的对象去完成时会产生不同的状态

//多态的条件：
//必须在继承体系下
//子类必须对父类的方法进行重写
//通过父类的引用调用重写方法

//向上转型：
//向上转型是多态的前提
//优点：让代码实现更简单灵活
//缺点：不能调用到子类特有的方法

/*class Animal{
    public String name;
    public int age;

    public void eat(){
        System.out.println(name+"正在吃饭！");
    }
}

class Dog extends Animal {

    public void wangWang(){
        System.out.println(name+"正在汪汪叫!");
    }
}
class Bird extends Animal{
    public String wing;

    public void fly(){
        System.out.println(name+"正在飞！");
    }
}

public class KnowledgeTwo {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "伊约";
        dog.eat();
        dog.wangWang();

        Bird bird = new Bird();
        bird.name = "圆圆";
        Animal animal2 = bird;

        Animal animal = dog;//向上转型
        //理论上来说，等号两边的数据类型必须一致,否则赋值会出错
    }
}*/



/*
class Animal{
    public String name;
    public int age;

    public void eat(){
        System.out.println(name+"正在吃饭！");
    }
}

class Dog extends Animal {

    public void wangWang(){
        System.out.println(name+"正在汪汪叫!");
    }
}
class Bird extends Animal{
    public String wing;

    public void fly(){
        System.out.println(name+"正在飞！");
    }
}

public class KnowledgeTwo {
    public static void main(String[] args) {
        Animal animal1 = new Dog();
        animal1.name = "小红";
        animal1.age = 2;
        animal1.eat();

        System.out.println("==========");

        Animal animal2 = new Dog();
        animal2.name = "小二";
        animal2.age = 3;
        animal2.eat();

        //理论上来说，等号两边的数据类型必须一致,否则赋值会出错

        //当发生向上转型之后，只能访问父类里的成员，不能访问子类特有的成员
    }
}
*/

/*class Animal{
    public String name;
    public int age;

    public void eat(){
        System.out.println(name+"正在吃饭！");
    }
}
class Dog extends Animal {
    public void eat(){
        System.out.println(name+"正在吃狗粮！");
    }
    public void wangWang(){
        System.out.println(name+"正在汪汪叫!");
    }
}
class Bird extends Animal{
    public String wing;

    public void eat(){
        System.out.println(name+"正在吃鸟粮！");
    }
    public void fly(){
        System.out.println(name+"正在飞！");
    }
}
public class KnowledgeTwo {
    public static void main(String[] args) {
        Animal animal1 = new Dog();//直接赋值式的向上转型
        animal1.name = "小红";
        animal1.age = 2;
        animal1.eat();

        System.out.println("==========");

        Animal animal2 = new Bird();////直接赋值式的向上转型
        animal2.name = "小二";
        animal2.age = 3;
        animal2.eat();
    }
}*/


//参数向上转型：

/*class Animal{
    public String name;
    public int age;

    public void eat(){
        System.out.println(name+"正在吃饭！");
    }
}

class Dog extends Animal {

    public void wangWang(){
        System.out.println(name+"正在汪汪叫!");
    }
}
class Bird extends Animal{
    public String wing;

    public void fly(){
        System.out.println(name+"正在飞！");
    }
}

public class KnowledgeTwo {
    public static void func(Animal animal){

    }
    public static void main(String[] args) {
        Dog dog = new Dog();
        func(dog);//这样也算向上转型，本来应该创一个Animal类型的，但是传的是Animal类型的子类Dog类型
    }
}*/



//返回值向上转型：
/*
class Animal{
    public String name;
    public int age;

    public void eat(){
        System.out.println(name+"正在吃饭！");
    }
}

class Dog extends Animal {

    public void wangWang(){
        System.out.println(name+"正在汪汪叫!");
    }
}
class Bird extends Animal{
    public String wing;

    public void fly(){
        System.out.println(name+"正在飞！");
    }
}

public class KnowledgeTwo {
    public static Animal func(){
        return new Dog();
    }
    public static void main(String[] args) {
    }
}
*/



//重写（override，也称覆盖）：方法名称相同，参数列表相同，返回值相同
//被private修饰的方法是不能被重写的
//static修饰的方法不能重写
//子类中重写的那个方法的访问修饰权限要大于等于父类中的那个被重写的方法的权限
//权限大小：private<默认权限（default）<protected<public
//被final修饰的方法是不能被重写的，此时这个方法叫做密封方法
//构造方法不能重写

//重写的设计原则：对于已经投入使用的类，尽量不要修改，最好的方法是重新定义一个新的类，来重复利用其中共性的内容，并且添加或者改动新的内容



/*class Animal{
    public String name;
    public int age;

    public void eat(){
        System.out.println(name+"正在吃饭！");
    }
}

class Dog extends Animal {

    public void wangWang(){
        System.out.println(name+"正在汪汪叫!");
    }
    @Override//注解，这个注解的意思是，当前这个方法是被重写的，它可以帮助我们检查重写是否出错
    public void eat(){
        System.out.println(name+"正在吃狗粮！");
    }
}
class Bird extends Animal{

    public String wing;

    public void fly(){
        System.out.println(name+"正在飞！");
    }

    @Override//注解，这个注解的意思是，当前这个方法是被重写的，它可以帮助我们检查重写是否出错
    public void eat(){
        System.out.println(name+"正在吃鸟粮！");
    }
}

public class KnowledgeTwo {
    public static void main(String[] args) {
        Animal animal1 = new Dog();
        animal1.name = "小名";
        animal1.eat();//小名正在吃狗粮！

        Animal animal2 = new Bird();
        animal2.name = "圆圆";
        animal2.eat();//圆圆正在吃鸟粮！

        //动态绑定：在运行的时候调用了重写的方法（动态绑定是发生多态的基础）
        //前提：向上转型，发生了重写，通过父类引用（注意是父类引用）来调用这个父类子类重写的方法
        //编译的时候还是父类，运行的时候用的是子类的--->动态绑定
    }
}*/


//静态绑定（也成为前期绑定，早绑定）：在编译的时候已经知道调用哪个方法了（比如：重载）
//动态绑定（后期绑定，晚绑定）：在运行的时候才能知道调用了哪个方法

/*class Animal{
    public String name;
    public int age;

    public void eat(){
        System.out.println(name+"正在吃饭！");
    }
}

class Dog extends Animal {
    public void wangWang(){
        System.out.println(name+"正在汪汪叫!");
    }
    @Override
    public void eat(){
        System.out.println(name+"正在吃狗粮！");
    }
}
class Bird extends Animal{
    public String wing;

    public void fly(){
        System.out.println(name+"正在飞！");
    }

    @Override
    public void eat(){
        System.out.println(name+"正在吃鸟粮！");
    }
}

public class KnowledgeTwo {
    public static void function(Animal animal){
        animal.eat();
    }
    public static void main(String[] args) {
        Animal animal1 = new Dog();
        animal1.name = "小名";
        function(animal1);

        Animal animal2 = new Bird();
        animal2.name = "圆圆";
        function(animal2);
    }
    //多态：当父类引用引用的对象不一样的时候，表现出的行为是不一样的
}*/



//向下转型

/*
class Animal{
    public String name;
    public int age;

    public void eat(){
        System.out.println(name+"正在吃饭！");
    }
}

class Dog extends Animal {
    public void eat(){
        System.out.println(name+"正在吃狗粮！");
    }
    public void wangWang(){
        System.out.println(name+"正在汪汪叫!");
    }
}

class Bird extends Animal{
    public String wing;

    public void eat(){
        System.out.println(name+"正在吃鸟粮！");
    }
    public void fly(){
        System.out.println(name+"正在飞！");
    }
}

public class KnowledgeTwo {
    public static void main(String[] args) {
        Animal animal = new Dog();//向上转型
        animal.name = "小黑";
        animal.age = 1;
        animal.eat();

        System.out.println();

        Bird bird = (Bird) animal;//向下转型
    }
}
*/



//如何修改，使其不报错
/*
class Animal{
    public String name;
    public int age;

    public void eat(){
        System.out.println(name+"正在吃饭！");
    }
}

class Dog extends Animal {

    public void wangWang(){
        System.out.println(name+"正在汪汪叫!");
    }
}

class Bird extends Animal{
    public String wing;

    public void fly(){
        System.out.println(name+"正在飞！");
    }
}

public class KnowledgeTwo {
    public static void main(String[] args) {
        Animal animal1 = new Animal();
        if(animal1 instanceof Dog){//可以理解为animal1这个引用是不是真的引用了Dog对象
            Dog dog = (Dog)animal1;
            dog.name = "小红";
            dog.wangWang();
        }

        System.out.println("============");

        Animal animal2 = new Animal();
        if(animal2 instanceof Bird){//可以理解为animal2这个引用是不是真的引用了Bird对象
            Bird bird = (Bird) animal2;
            bird.fly();
        }
    }
}
*/

/*class Animal{
    public String name;
    public int age;

    public void eat(){
        System.out.println(name+"正在吃饭！");
    }
}

class Dog extends Animal {
    public void eat(){
        System.out.println(name+"正在吃狗粮！");
    }
    public void wangWang(){
        System.out.println(name+"正在汪汪叫!");
    }
}

class Bird extends Animal{
    public String wing;

    public void eat(){
        System.out.println(name+"正在吃鸟粮！");
    }
    public void fly(){
        System.out.println(name+"正在飞！");
    }
}

public class KnowledgeTwo {
    public static void main(String[] args) {
        Animal animal = new Dog();//向上转型
        animal.name = "小黑";
        animal.age = 1;
        animal.eat();

        System.out.println();

        if(animal instanceof Bird){
            Bird bird = (Bird) animal;//向下转型
            bird.name = "小飞";
            bird.age = 2;
            bird.eat();
            bird.fly();
        }
        if(animal instanceof Dog){
            Dog dog1 = (Dog)animal;
            dog1.name = "小白";
            dog1.age = 1;
            dog1.eat();
            dog1.wangWang();
        }
    }
}*/




//多态的优缺点：

//使用多态的好处：降低代码的“圈复杂度”，避免大量使用if-else语句
//所谓圈复杂度，简单来理解就是，一段代码中条件和循环语句的个数
//如果一个代码中圈复杂度过高，就要考虑重构
//不同公司对于代码圈复杂度的标准不一样，一般不会超过10

//使用多态的缺点：代码的运行效率低

//属性没有多态性：当父类和子类都有同名属性的时候，通过父类引用，只能引用父类自己的成员属性
//构造方法，没有多态性。


/*class Shape{
    public void draw(){
        System.out.println("画图形！");
    }
}

class Rect extends Shape {
    @Override
    public void draw() {
        System.out.println("⬜");
    }
}

class Cycle extends Shape {
    @Override
    public void draw() {
        System.out.println("⚪");
    }
}

class Flower extends Shape{
    @Override
    public void draw() {
        System.out.println("❀");
    }
}

public class KnowledgeTwo {
    public static void drawMap(Shape shape) {
        shape.draw();
    }
    public static void main(String[] args) {
        Rect rect = new Rect();
        drawMap(rect);

        Cycle cycle = new Cycle();
        drawMap(cycle);

        Flower flower = new Flower();
        drawMap(flower);
    }
}*/


//不使用多态按顺序打印：⚪ ⬜ ⚪ ⬜ ❀

/*
class Shape{
    public void draw(){
        System.out.println("画图形！");
    }
}

class Rect extends Shape {
    @Override
    public void draw() {
        System.out.println("⬜");
    }
}

class Cycle extends Shape {
    @Override
    public void draw() {
        System.out.println("⚪");
    }
}

class Flower extends Shape{
    @Override
    public void draw() {
        System.out.println("❀");
    }
}
public class KnowledgeTwo {
    public static void drawMap(Shape shape) {
        shape.draw();
    }
    public static void main(String[] args) {
        Rect rect = new Rect();
        Cycle cycle = new Cycle();
        Flower flower = new Flower();
        //顺序：⚪ ⬜ ⚪ ⬜ ❀

        String[] shapes = {"cycle", "rect", "cycle", "rect", "flower"};
        for (String s : shapes) {
            if (s.equals("cycle")) {
                drawMap(cycle);
            }
            if (s.equals("rect")) {
                drawMap(rect);
            }
            if (s.equals("flower")) {
                drawMap(flower);
            }
        }
    }
}*/





//使用多态按顺序打印：⚪ ⬜ ⚪ ⬜ ❀
/*class Shape{
    public void draw(){
        System.out.println("画图形！");
    }
}

class Square extends Shape {
    @Override
    public void draw() {
        System.out.println("⬜");
    }
}

class Cycle extends Shape {
    @Override
    public void draw() {
        System.out.println("⚪");
    }
}

class Flower extends Shape{
    @Override
    public void draw() {
        System.out.println("❀");
    }
}
public class KnowledgeTwo {
    public static void drawMap() {
        Square square = new Square();
        Cycle cycle = new Cycle();
        Flower flower = new Flower();
        //顺序：⚪ ⬜ ⚪ ⬜ ❀
        Shape[] shapes = {cycle, square, cycle, square, flower};
        //发生了向上转型
        for (Shape shape: shapes) {
            shape.draw();
        }
    }
    public static void main(String[] args) {
        drawMap();
    }
}*/


//避免在构造方法中调用重写的构造方法

//注意：当在父类的构造方法中去调用父类和子类重写的构造方法的时候，会调用子类的
/*class B{
    public B(){//父类的构造方法
        func();
    }

    public void func(){
        System.out.println("B.func");
    }
}

class D extends B{
    private int num = 1;

    public void func(){//被重写
        System.out.println("D.func"+ num);//num为0，因为此时连父类的初始化都没有完成
    }
}
public class KnowledgeTwo {
    public static void main(String[] args) {
        D d = new D();
    }
}*/
